/*
 * ====================================================================
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.dromara.common.core.utils.concurrent;

import cn.hutool.core.lang.Assert;

import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;

public class Async {

    private java.util.concurrent.Executor concurrentExec;

    public static Async instance;

    private static Async newInstance() {
        return new Async();
    }

    public static Async getInstance() {
        if (instance == null) {
            synchronized (Boolean.TRUE) {
                if (instance == null) {
                    instance = newInstance();
                }
            }
        }

        return instance;
    }

    public String name;

    Async() {
        super();
    }

    public void setName(String name) {
        this.name = name;
    }

    public Async use(final Executor concurrentExec) {
        this.concurrentExec = concurrentExec;
        return this;
    }

    public <T> Future<T> execute(final String name, final Callable callable, final FutureCallback<T> callback) {
        final BasicFuture<T> future = new BasicFuture<T>(callback);
        final ExecRunnable<T> runnable = new ExecRunnable<T>(name, callable,
            future);
        if (this.concurrentExec != null) {
            this.concurrentExec.execute(runnable);
        } else {
            final Thread t = new Thread(runnable);
            t.setDaemon(true);
            t.start();
        }
        return future;
    }

    public <T> Future<T> execute(String name, final Callable callable) {
        Assert.notNull(name);
        Assert.notNull(callable);
        return execute(name, callable, null);
    }

    public <T> Future<T> execute(final Callable callable) {
        return execute(Thread.currentThread().getName(), callable);
    }

}
